package cn.bigfire.compiler.mytest.lexer01;

import cn.bigfire.compiler.util.CharUtil;
import lombok.SneakyThrows;
import org.junit.Test;

import java.io.CharArrayReader;
import java.util.ArrayList;
import java.util.List;

public class Lexers {

    @Test
    @SneakyThrows
    public void test001() {
        printTokens(tokenize("int a = 5"));
        printTokens(tokenize("int a = 3+5"));
        printTokens(tokenize("2+4"));
        printTokens(tokenize("1+3*5"));
        printTokens(tokenize("(1+3)*5"));
    }
    
    
    @SneakyThrows
    public static List<Token> tokenize(String code) {
        List<Token> tokens = new ArrayList<>();
        StringBuilder tokenTmp = new StringBuilder();
        CharArrayReader reader = new CharArrayReader(code.toCharArray());
        int ich = 0;
        char ch = 0;
        while ((ich = reader.read()) != -1) {
            ch = (char) ich;
            if (tokenTmp.length() <= 0) {//空状态  初始状态
                if (CharUtil.isAlpha(ch)) {
                    tokenTmp.append(ch);
                } else if (CharUtil.isDigit(ch)) {
                    tokenTmp.append(ch);
                } else if ('=' == ch) {
                    tokens.add(new Token(TokenType.Assignment, ch + ""));
                } else if (';' == ch) {
                    tokens.add(new Token(TokenType.SemiColon, ch + ""));
                } else if ('+' == ch) {
                    tokens.add(new Token(TokenType.Plus, ch + ""));
                } else if ('-' == ch) {
                    tokens.add(new Token(TokenType.Minus, ch + ""));
                } else if ('*' == ch) {
                    tokens.add(new Token(TokenType.Star, ch + ""));
                } else if ('/' == ch) {
                    tokens.add(new Token(TokenType.Slash, ch + ""));
                } else if ('(' == ch) {
                    tokens.add(new Token(TokenType.LeftParen, ch + ""));
                } else if (')' == ch) {
                    tokens.add(new Token(TokenType.RightParen, ch + ""));
                } else if (CharUtil.isBlank(ch)) {//成功截取一个token
                    continue;//跳过空白开头
                }
            } else {//有数据状态
                if (CharUtil.isAlpha(tokenTmp.charAt(0))) {//字母开头
                    if (CharUtil.isAlpha(ch)) {
                        tokenTmp.append(ch);
                    } else if (CharUtil.isDigit(ch)) {
                        tokenTmp.append(ch);
                    } else if ('=' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Assignment, ch + ""));
                    } else if (';' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.SemiColon, ch + ""));
                    } else if ('+' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Plus, ch + ""));
                    } else if ('-' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Minus, ch + ""));
                    } else if ('*' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Star, ch + ""));
                    } else if ('/' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Slash, ch + ""));
                    } else if ('(' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.LeftParen, ch + ""));
                    } else if (')' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.RightParen, ch + ""));
                    } else if (CharUtil.isBlank(ch)) {//成功截取一个token
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                    }

                } else if (CharUtil.isDigit(tokenTmp.charAt(0))) {//数字开头
                    if (CharUtil.isAlpha(ch)) {
                        tokenTmp.append(ch);
                    } else if (CharUtil.isDigit(ch)) {
                        tokenTmp.append(ch);
                    } else if ('=' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Assignment, ch + ""));
                    } else if (';' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.SemiColon, ch + ""));
                    }else if ('+' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Plus, ch + ""));
                    } else if ('-' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Minus, ch + ""));
                    } else if ('*' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Star, ch + ""));
                    } else if ('/' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.Slash, ch + ""));
                    } else if ('(' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.LeftParen, ch + ""));
                    } else if (')' == ch) {
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                        tokens.add(new Token(TokenType.RightParen, ch + ""));
                    } else if (CharUtil.isBlank(ch)) {//成功截取一个token
                        if (tokenTmp.toString().length() > 0) {
                            tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
                            tokenTmp = new StringBuilder();//重置
                        }
                    }
                }
            }
        }
        //结束时如果tokenTmp中还有数据，则加入token列表
        if (tokenTmp.length() > 0) {
            char c = tokenTmp.charAt(0);
            if (CharUtil.isAlpha(tokenTmp.charAt(0))) {//字母开头
                tokens.add(new Token(TokenType.ID, tokenTmp.toString()));
            } else if (CharUtil.isDigit(tokenTmp.charAt(0))) {
                tokens.add(new Token(TokenType.Number, tokenTmp.toString()));
            } else if ('=' == ch) {
                tokens.add(new Token(TokenType.Assignment, tokenTmp.toString()));
            } else if (';' == ch) {
                tokens.add(new Token(TokenType.SemiColon, tokenTmp.toString()));
            }else if ('+' == ch) {
                tokens.add(new Token(TokenType.Plus, tokenTmp.toString()));
            }else if ('-' == ch) {
                tokens.add(new Token(TokenType.Minus, tokenTmp.toString()));
            }else if ('*' == ch) {
                tokens.add(new Token(TokenType.Star, tokenTmp.toString()));
            }else if ('/' == ch) {
                tokens.add(new Token(TokenType.Slash, tokenTmp.toString()));
            }else if ('(' == ch) {
                tokens.add(new Token(TokenType.LeftParen, tokenTmp.toString()));
            }else if (')' == ch) {
                tokens.add(new Token(TokenType.RightParen, tokenTmp.toString()));
            }
        }
        

        return tokens;
    }


    /**
     * 打印token列表
     *
     * @param tokens token列表
     */
    public static void printTokens(List<Token> tokens) {
        System.out.println("---------------------");
        for (Token token : tokens) {
            System.out.println(token.getText() + "\t\t" + token.getTokenType());
        }
        System.out.println("---------------------");
    }
}
